#pragma once
// 异步工作器（线程）
/*
    处理 ‘第二个’ 缓冲区中的数据
    缓冲区没有数据，进行交换缓冲

    实现：
        1. 成员：
            双缓冲区【生产、消费】
            互斥锁
            条件变量【生产&消费】（交换阻塞）
            回调函数【数据处理接口：外界传入一个函数，告诉异步工作器该如何处理数据】
        2. 方法：
            停止异步工作器
            添加数据至缓冲区
            创建线程【交换缓冲区】
*/
#include "6_buffer.hpp"
#include <mutex>
#include <thread>
#include <condition_variable>
#include <functional>
#include <memory>
#include <atomic>

namespace senlog
{
    using Functor = std::function<void(Buffer &)>;
    enum class AsyncType
    {
        ASYNC_SAFE,   // 缓冲区满   阻塞    实际生产
        ASYNC_UUNSAFE // 缓冲区满了 扩容    压力测试
    };  //解耦 buffer只需要push数据
    class AsynLooper
    {
    private:
        AsyncType _asynctype;
        Buffer _productor_buf;
        Buffer _consumer_buf;
        std::mutex _mutex;
        std::condition_variable _pro_cond;
        std::condition_variable _con_cond;

        std::atomic<bool> _stop; // 是否停止 AysnLooper
        std::thread _thread;

    public:
        using ptr = std::shared_ptr<AsynLooper>; // ?
        AsynLooper(const Functor &callback, AsyncType aysnctype = AsyncType::ASYNC_SAFE)
            : _stop(false)
            , _thread(std::thread(&AsynLooper::Rountine, this))
            , _callBack(callback)
            , _asynctype(AsyncType::ASYNC_SAFE)
        {
        }
        ~AsynLooper()
        {
            stop();
        }
        void stop()
        {
            // 可能其他线程会访问这个变量,设置为原子操作
            _stop = true;
            _con_cond.notify_all(); // 唤醒工作线程
            _thread.join();
        }
        // 业务线程调用该函数进行数据的写入(prodeuctor_buf)
        void push(const char *data, size_t len)
        {
            // 无限扩容 ： 非安全状态
            // 固定大小，阻塞
            std::unique_lock<std::mutex> lock(_mutex);
            if (_asynctype == AsyncType::ASYNC_SAFE)
            {   //需要阻塞
                _pro_cond.wait(lock, [&]()
                               { return _productor_buf.writeableSize() >= len; }); // 第二个参数要是一个可调用对象，函数等
            }
            // bool cd = _productor_buf.writeableSize() >= len; 【err】

            _productor_buf.push(data, len);
            // 唤醒消费者
            _con_cond.notify_one();
        }

    private:
        void Rountine() // 线程入口函数
        {
            // 对缓冲区内的格式化字符串进行落地输出
            // 处理完毕后 初始化缓冲区
            // 再交换缓冲区（循环）
            while (1)
            {
                // 先判断 生产缓冲区有无数据
                {
                    std::unique_lock<std::mutex> lock(_mutex);

                    if(_stop && _productor_buf.empty()) break;

                    _con_cond.wait(lock, [&]()
                                   { return !_productor_buf.empty() || _stop; });
                    // 有数据， 交换
                    _productor_buf.swapBuffer(_consumer_buf);
                    // 唤醒生产者
                    if(_asynctype == AsyncType::ASYNC_SAFE)
                        _pro_cond.notify_all();
                } ///////////这里定义一个作用域，作用是让lock出作用域解锁

                // 确保consummer_buf是有数据的，进行处理
                _callBack(_consumer_buf);
                // 处理完毕，初始化缓冲区
                _consumer_buf.resetBuffer();
            }
        }
    public:
        Functor _callBack; // 由工作器使用者传入 回调函数
    };
};
